package org.andes.kownledge.operator;

import java.util.List;

import org.andes.kownledge.operator.func.Cond;
import org.andes.kownledge.operator.func.During;
import org.andes.kownledge.operator.func.Func;
import org.andes.kownledge.operator.func.FuncBuilder;
import org.armedbear.lisp.Cons;
import org.armedbear.lisp.Fixnum;
import org.armedbear.lisp.LispObject;
import org.armedbear.lisp.SimpleString;
import org.armedbear.lisp.SingleFloat;
import org.armedbear.lisp.Symbol;

public class TermBuilder {
	
	
	
//	 type.equalsIgnoreCase("not")||
//	 type.equalsIgnoreCase("in-wm")||
//	 type.equalsIgnoreCase("wm-or-derive")||
//	 type.equalsIgnoreCase("add-to-wm")||
//	 type.equalsIgnoreCase("test")||
//	 type.equalsIgnoreCase("any-member")||
//	 type.equalsIgnoreCase("debug")||
//	 type.equalsIgnoreCase("rdebug")||
//	 type.equalsIgnoreCase("count")||
//	 type.equalsIgnoreCase("setof");
	public static Executable buildExecutable(LispObject lo){
		LispObject name=((Cons) lo).car();		
		String type=((Symbol)name).getName();
		if(type.equalsIgnoreCase("bind")){
			return Executable.buildBind(lo);
		}else if(type.equalsIgnoreCase("not")){
			return Executable.buildNot(lo);
		}else if(type.equalsIgnoreCase("in-wm")){
			return Executable.buildInwm(lo);
		}else if(type.equalsIgnoreCase("wm-or-derive")){
			return Executable.buildWmOrDerive(lo);
		}else if(type.equalsIgnoreCase("add-to-wm")){
			return Executable.buildAddToWm(lo);
		}else if(type.equalsIgnoreCase("test")){
			return Executable.buildTest(lo);
		}else if(type.equalsIgnoreCase("any-member")){
			return Executable.buildAnyMember(lo);
		}else if(type.equalsIgnoreCase("count")){
			return Executable.buildCount(lo);
		}else if(type.equalsIgnoreCase("setof")){
			return Executable.buildSetof(lo);
		}else if(type.equalsIgnoreCase("debug")){
			return Executable.buildDebug(lo);
		}else if(type.equalsIgnoreCase("RDEBUG")){
			return Executable.buildReDebug(lo);
		}
		return null;
	}
	public static Macro buildMacro(LispObject lo){
		LispObject name=((Cons) lo).car();		
		String type=((Symbol)name).getName();
		if(type.equalsIgnoreCase("map")){
			MapMacro map=new MapMacro();
			return map;
		}else if(type.equalsIgnoreCase("foreach")){
			Foreach foreach=new Foreach();
			return foreach;
		}
		
		System.out.println("There is error in buildMacro");
		return null;
	}
	
	public static Term buildTerm(LispObject lo) {
		if (lo instanceof Fixnum)
			return buildNumber((Fixnum) lo);
		else if (lo instanceof SingleFloat)
			return buildNumber((SingleFloat) lo);
		else if (lo instanceof SimpleString)
			return buildComment((SimpleString) lo);		
		else if (lo instanceof Symbol)
			return buildAtom((Symbol) lo);
		else if (executable_p(lo)) {
			return buildExecutable(lo);
		} else if (precond_macro_p(lo)) {
			return buildMacro(lo);
		} else if (function_p(lo)) {
			return buildFunc(lo);
		} else if(executable_p(lo)){
			return buildExecutable(lo);
			
		}else{
			return buildPredication(lo);
		}
	}
	private static Term buildNumber(Fixnum lo) {
		return new Num(lo.value);
	}
	private static Term buildComment(SimpleString lo) {
		return new Comment(lo.getStringValue());
	}
	private static Term buildNumber(SingleFloat lo) {
		return new FloatNum(lo.value);
	}
	public static Predication buildPredication(LispObject lo){
		LispObject name = ((Cons) lo).car();
		if(name instanceof Symbol){
			String type = ((Symbol) name).getName();
			Predication pred = new Predication();
			pred.setPredicate(type);
			if(lo.cdr() instanceof Cons){
				List<LispObject> list=((Cons)lo.cdr()).toList();
				for(int i=0;i<list.size();i++){
					LispObject elem=list.get(i);
					Term para=buildTerm(elem);
					if(para instanceof Key){
						if(i+1<list.size()){
							Term value=buildTerm(list.get(i+1));
							((Key)para).setValue(value);
							i++;
						}
						
						pred.addKey((Key) para);
					}else
						pred.addArgument(para);
				}
			}else{
				Term term=buildTerm(lo.cdr());
				pred.addArgument(term);
			}
			
			
			return pred;
		}else
			return null;
		
	}
	private   static boolean executable_p(Object op){
		if(op instanceof Cons){
			LispObject name=((Cons) op).car();
			if(name instanceof Symbol){
				String type=((Symbol)name).getName();
				return type.equalsIgnoreCase("bind")||
				 type.equalsIgnoreCase("not")||
				 type.equalsIgnoreCase("in-wm")||
				 type.equalsIgnoreCase("wm-or-derive")||
				 type.equalsIgnoreCase("add-to-wm")||
				 type.equalsIgnoreCase("test")||
				 type.equalsIgnoreCase("any-member")||
				 type.equalsIgnoreCase("debug")||
				 type.equalsIgnoreCase("rdebug")||
				 type.equalsIgnoreCase("count")||				
				 type.equalsIgnoreCase("setof");
				
				
			}
		}
		return false;
	}
	private   static boolean function_p(Object op){
		if(op instanceof Cons){
			LispObject name=((Cons) op).car();
			if(name instanceof Symbol){
				String type=((Symbol)name).getName();
				return type.equalsIgnoreCase("and")||
				 type.equalsIgnoreCase("BODY-NAME")||
				 type.equalsIgnoreCase("CDR")||
				 type.equalsIgnoreCase("componentp")||
				 type.equalsIgnoreCase("cond")||
				 type.equalsIgnoreCase("cons")||
				 type.equalsIgnoreCase("CROSS-PRODUCT-DIR")||
				 type.equalsIgnoreCase("DEFINITE-DIRECTIONP")||
				 type.equalsIgnoreCase("DEGREE-SPECIFIERP")||
				 type.equalsIgnoreCase("DIR-VAR-VALUE")||
				 type.equalsIgnoreCase("DURING")||
				 type.equalsIgnoreCase("DNUM")||
				 type.equalsIgnoreCase("eq")||
				 type.equalsIgnoreCase("eql")||
				 type.equalsIgnoreCase("equal")||
				 type.equalsIgnoreCase("error")||
				 type.equalsIgnoreCase("FIND")||
				 type.equalsIgnoreCase("first")||
				 type.equalsIgnoreCase("FORMAT-SYM")||
				 type.equalsIgnoreCase("if")||
				 type.equalsIgnoreCase("GET-ANGLE-BETWEEN")||
				 type.equalsIgnoreCase("LENGTH")||
				 type.equalsIgnoreCase("list")||
				 type.equalsIgnoreCase("listp")||
				 type.equalsIgnoreCase("member")||
				 type.equalsIgnoreCase("MINIMAL-X-ROTATIONS")||
				 type.equalsIgnoreCase("NON-ZERO-PROJECTIONP")||
				 type.equalsIgnoreCase("not")||
				 type.equalsIgnoreCase("null")||
				 type.equalsIgnoreCase("numberp")||
				 type.equalsIgnoreCase("OPPOSITE")||
				 type.equalsIgnoreCase("or")||
				 type.equalsIgnoreCase("ORDERLESS-P")||
				 type.equalsIgnoreCase("PARAMETER-OR-UNKNOWNP")||
				 type.equalsIgnoreCase("PERPENDICULARP")||
				 type.equalsIgnoreCase("PROBLEM-CHOICES")||
				 type.equalsIgnoreCase("PROBLEM-IGNOREPSMS")||	 
				 type.equalsIgnoreCase("PROPER-SUBINTERVALP")||	 
				 type.equalsIgnoreCase("quote")||
				 type.equalsIgnoreCase("REMOVE-DUPLICATES")||
				 type.equalsIgnoreCase("REMOVE-TIME")||
				 type.equalsIgnoreCase("REST")||
				 type.equalsIgnoreCase("SCALAR-QUANTITYP")||
				 type.equalsIgnoreCase("SECOND")||
				 type.equalsIgnoreCase("SET-DIFFERENCE")||
				 type.equalsIgnoreCase("SET-TIME")||
				 type.equalsIgnoreCase("SORT")||
				 type.equalsIgnoreCase("THIRD")||
				 type.equalsIgnoreCase("SUCCESSIVE-INTERVALS")||
				 type.equalsIgnoreCase("TENDPOINTP")||
				 type.equalsIgnoreCase("TIME-ABBREV")||
				 type.equalsIgnoreCase("TIME-CONSECUTIVEP")||
				 type.equalsIgnoreCase("TIME-INTERVALP")||
				 type.equalsIgnoreCase("TIME-OF")||
				 type.equalsIgnoreCase("TIME-POINTP")||
				 type.equalsIgnoreCase("TINSIDEP")||
				 type.equalsIgnoreCase("TINSIDEP-INCLUDE-ENDPOINTS")||
				 type.equalsIgnoreCase("ZDIR-PHI")||
				 type.equalsIgnoreCase("cons")
				 
				 ;
				
			}
		}
		return false;
	}
	
	
//	(defun precond-macro-p (M)
//	  "Return t iff Exp is a Macro expression."
//	  (and (listp M)
//	       (member (car M) '(foreach map))))
	private static  boolean  precond_macro_p(LispObject lo){
		if(lo instanceof Cons){
			LispObject o=lo.car();
			if(o instanceof Symbol){
				String name=((Symbol)o).getName();
				return name.equalsIgnoreCase("foreach")|| name.equalsIgnoreCase("map");
			}else
				return false;
			
			
		}
		return false;
	}
	
//	private static Term buildAtom1(LispObject o){
//		if(o instanceof Symbol){
//			return buildAtom(o);			
//		}
////		else if(o instanceof Cons){
////			return buildFunc(o);
////			
////		}
//		return  null;
//	}
	public static Term buildAtom(Symbol lo) {
		String s = lo.getName();
		if (s.substring(0, 1).equals("?")) {
			return new Variable(s.substring(1));
		} else if (((org.armedbear.lisp.Package)lo.getPackage()).getName().equalsIgnoreCase("KEYWORD")) {
			return new Key(s);
		}else
			return new Constant(s);
	}
	public static Term buildNum(Fixnum lo) {		
		return new Num(lo.value);
	}
	
	public static Func buildFunc(LispObject lo){
		if(lo instanceof Cons){
			List<LispObject> parts=((Cons)lo).toList();
			if(parts.get(0) instanceof Symbol){
				String funname=((Symbol)parts.get(0)).getName();
				if(funname.equalsIgnoreCase("COND")){
					return buildCond(lo);
				}else{//common fun
					//List<Term> params=new ArrayList<Term>();
					Func fun=FuncBuilder.getFunc(funname);
					
					for(int i=1;i<parts.size();i++){
						if(parts.get(i) instanceof Symbol){
							Term para=buildAtom((Symbol) parts.get(i));
							if(para instanceof Key){
								if(i+1<parts.size()){
									Term value=buildTerm(parts.get(i+1));
									((Key)para).setValue(value);
									i++;
								}
								
								fun.addKey((Key) para);
							}else
								fun.addVar(para);
						}else if(parts.get(i) instanceof Cons){
							Term para=buildFunc(parts.get(i));
							fun.addVar(para);
						}else if(parts.get(i) instanceof Fixnum){
							Term para=buildNum((Fixnum) parts.get(i));
							fun.addVar(para);
							
						}
						
							
					}	
					if(fun instanceof During&&fun.getVars().size()==0)
						System.out.println("during vars size:"+fun.getVars().size());
					return fun;
				}
				
			}else if(parts.get(0) instanceof Cons){
				return null;
			}
			return null;
			
		}else{
			return null;
			
		}
		
	}
	
	public static Func buildCond(LispObject lo){
		if(lo instanceof Cons){
			List<LispObject> parts=((Cons)lo).toList();
			if(parts.get(0) instanceof Symbol){
				Cond cond=new Cond();
				for(int i=1;i<parts.size();i++){
					
					if(parts.get(i) instanceof Cons){
						Cons condpair=(Cons) parts.get(i);
						LispObject condo=condpair.car();
						Term condt=buildTerm(condo);
						LispObject funco=condpair.car();
						Term funct=buildTerm(funco);
						cond.addCondPair(condt, funct);
						
					}
						
				}	
				
				return cond;
			}else if(parts.get(0) instanceof Cons){
				return null;
			}
			return null;
			
		}else{
			return null;
			
		}
		
	}
			
}
